package com.vois.jack.btmgr.devices.WL100Dev;

import android.bluetooth.BluetoothProfile;
import android.os.Bundle;
import android.os.Message;

import com.vois.jack.btmgr.classicbase.BtDevCommonMsg;
import com.vois.jack.btmgr.classicbase.BtDevConstant;
import com.vois.jack.btmgr.classicbase.BtDevice;
import com.vois.jack.btmgr.classicbase.BtHelper;
import com.vois.jack.btmgr.classicbase.BtRecorderInterface;
import com.vois.jack.btmgr.classicbase.BtScoRecorder;
import com.vois.jack.btmgr.classicbase.BtSppRecorder;
import com.vois.jack.btmgr.common.IBtConstants;
import com.vois.jack.btmgr.util.Logger;

import java.io.UnsupportedEncodingException;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;

public class WL100BtDev extends BtDevice {
    private Logger logger = Logger.getLogger(WL100BtDev.class);
    private BtSppRecorder btSppRecorder;
    private BtScoRecorder btScoRecorder;
    private byte[] recvBuf;
    private int recvState = RECV_STATE_READ_INIT;
    private boolean isToneMute;

    private boolean isV200;
    private String handMicVersion;
    private boolean handMicConnected;
    private PacketData curPacketData;
    private int curRecvSize;
    private Timer heartbeatTimer;

    private static final int MAX_PACKET_SIZE = 1024;
    private static final int MAX_RECVBUF_SIZE = 4 * MAX_PACKET_SIZE;
    private static final String HANDMIC_BRAND = "VL-V";
    private static final String HANDMIC_OLD_VERSION = "VL-V100";
    private static final String HANDMIC_PACKET = "HANDMIC_PACKET";
    private static final int RECV_STATE_READ_INIT = 0;
    private static final int RECV_STATE_READ_DATA = 1;
    private static final int RECV_STATE_READ_AUDIO = 2;
    private static final int RECV_STATE_READ_CMD = 3;
    private static final int AUDIO_PACKET_LEN = 128;

    private static final byte SPP_MAIN_CMD_POC_TYPE = (byte) 0xB0;
    private static final byte SPP_MAIN_CMD_KEY_TYPE = (byte) 0xC0;
    private static final byte SPP_SUB_CMD_POC_KEY = (byte) 0xB1;
    private static final byte SPP_POC_POC_SUB_VOLUMN = (byte) 0xB2;
    private static final byte SPP_POC_POC_STATE_HEADSET = (byte) 0xB3;
    private static final byte SPP_SUB_CMD_KEY_SHORT = (byte) 0xC1;
    private static final byte SPP_SUB_CMD_KEY_LONG = (byte) 0xC2;
    private static final byte SPP_SUB_CMD_KEY_DOUBLE = (byte) 0xC3;

    private static final byte KEYMSG_POC_PRESS = (byte) 0xE0;
    private static final byte KEYMSG_POC_RELEASE = (byte) 0xE1;
    private static final byte KEYMSG_KEY_SOS = (byte) 0xE2;
    private static final byte KEYMSG_KEY_VOL_UP = (byte) 0xE3;
    private static final byte KEYMSG_KEY_VOL_DOWN = (byte) 0xE4;
    private static final byte KEYMSG_KEY_ACCEPT = (byte) 0xE5;
    private static final byte KEYMSG_KEY_REJECT = (byte) 0xE6;
    private static final byte KEYMSG_KEY_PREV = (byte) 0xE7;
    private static final byte KEYMSG_KEY_NEXT = (byte) 0xE8;
    private static final byte KEYMSG_KEY_ANCHOR = (byte) 0xE9;

    public WL100BtDev() {
        logger.d( "WL100BtDev: ");
    }

    @Override
    protected void onSppSocketConnecting() {
        super.onSppSocketConnecting();
        logger.d("onSppSocketConnecting");
        curRecvSize = 0;
        recvState = RECV_STATE_READ_INIT;
    }

    private int initProcessor(byte[] buf, int dataSize, int bufPos) {
        logger.d( "initProcessor: dataSize:" + dataSize + " bufPos:" + bufPos);
        while (bufPos + 14 <= dataSize) {
            if (buf[bufPos] == '@' && buf[bufPos + 1] == '@') {
                String initStr = new String(buf, bufPos + 2, 12);
                logger.d( "initProcessor: initStr:" + initStr);
                if (initStr.contains(HANDMIC_BRAND)) {
                    handMicConnected = true;
                    isV200 = !initStr.contains(HANDMIC_OLD_VERSION);
                    logger.d( "initProcessor: isV200:" + isV200);

                    handMicVersion = initStr.substring(3);

                    // TODO: 19-4-15 telling activity that hand mic is initialized
                    // sending init flag to execute init processor
                    setToneVolume();
                    sendData(WLHandMicConstant.SPP_PHONE_INIT_MAIN_CMD, (byte) 0, null, (byte) 0);
                    sendSystemTime();
                    if (isV200) {
                        sendLangType((byte) 0);
                    }

                    recvState = RECV_STATE_READ_DATA;

                    if (getListener() != null) {
                        Message message = Message.obtain();
                        message.what = BtDevCommonMsg.BT_DEV_COMMON_READY_IND.getValue();
                        getListener().onMessage(this, message);
                    }

                    logger.d( "initProcessor: Device is ready");
                    // add timer for 1 min to synchronize time of handmic.
                    heartbeatTimer = new Timer();
                    heartbeatTimer.schedule(new TimerTask() {
                        @Override
                        public void run() {
                            if (handMicConnected) {
                                sendSystemTime();
                            }
                        }
                    }, 10000, 120000);
                    return bufPos + 14;
                }
            }

            bufPos++;
        }

        return bufPos;
    }

    @Override
    protected void onSppSocketDisconnected() {
        super.onSppSocketDisconnected();
        logger.d( "onSppSocketDisconnected: ");
        if (heartbeatTimer != null) {
            heartbeatTimer.cancel();
            heartbeatTimer = null;
        }
        handMicConnected = false;
    }



    private int dataProcessor(byte[] buf, int dataSize, int bufPos) {
        for (int i = bufPos; i < dataSize; i++) {
            if (buf[i] == PacketData.PACKET_HEAD_FLAG) {
                recvState = RECV_STATE_READ_CMD;
                logger.d( "dataProcessor: got command data");
                return i;
            }
            if (buf[i] == '@') {
                //Audio Packet
                if ((i+3 < dataSize)
                        && buf[i+1] == 'A'
                        && buf[i+2] == 'D'
                        && buf[i+3] == '@') {
                    recvState = RECV_STATE_READ_AUDIO;
                    return i;
                }
            }
        }

        logger.e( "dataProcessor: got nothing correct");
        logger.dumpArray(buf, dataSize);
        return dataSize;
    }

    private int audioProcessor(byte[] buf, int dataSize, int bufPos) {
        logger.d( "audioProcessor: bufPos:" + bufPos + " dataSize:" + dataSize);
        if (bufPos + AUDIO_PACKET_LEN > dataSize) {
            logger.e("dataSize: " + dataSize + " bufPos:" + bufPos);
            return bufPos;
        }

        if(btSppRecorder != null) {
            int ret = btSppRecorder.putRecordData(buf, bufPos + 4, AUDIO_PACKET_LEN - 4);
            if(ret == -1) {
                logger.e( "audioProcessor: put raw data error!!!!");
            }
        }else {
            logger.e("btSppRecorder is null!!!!!");
        }

        recvState = RECV_STATE_READ_DATA;
        return bufPos + AUDIO_PACKET_LEN;
    }

    private boolean constructPacketData(byte[] buf, PacketData packetData, int recvSize) {
        int packetSize, i;
        short checkSum = 0, packetChecksum;
        int offset;

        if(packetData == null) {
            return false;
        }

        packetSize = (((int)buf[1] & 0xFF) << 8);
        packetSize += ((int)buf[0] & 0xFF);

        logger.d( "constructPacketData: packetSize:" + packetSize);

        if((recvSize - 2) != packetSize) { //checksum got 2 bytes, need to minus it.
            logger.d( "constructPacketData: size is not consist");
            return false;
        }

        for(i = 0; i < packetSize; i++)
        {
            checkSum += (short)((short)buf[i] & 0xFF);
        }
        packetChecksum = (short)((short)buf[packetSize + 1] & 0xFF);
        packetChecksum = (short)((packetChecksum << 8) + ((short)buf[packetSize] & 0xFF));

        logger.d( "constructPacketData: calSum:" + checkSum + " recvSum:" + packetChecksum);
        if(packetChecksum != checkSum) {
            logger.d( "constructPacketData: checksum is not right");
            return false;
        }

        packetData.mainCmd = buf[2];
        packetData.subCmd = buf[3];
        packetData.packetId = buf[4];

        if(packetData.packetId == (byte)0x80) {
            packetData.dataSize = (((int)buf[6] & 0xFF) << 8);
            packetData.dataSize += ((int)buf[5] & 0xFF);
            offset = 0;
            packetData.data = new byte[packetData.dataSize];
            if (packetData.dataSize == (packetSize - 7)) {
                packetData.isPacketValid = true;
            }
        } else {
            offset = (((int)buf[6] & 0xFF) << 8);
            offset += ((int)buf[5] & 0xFF);

            if (packetData.dataSize == (offset + (packetSize - 7))) {
                packetData.isPacketValid = true;
            }
        }

        for(i = offset; i < recvSize - 9; i++) {
            packetData.data[i] = buf[7 + i];
        }

        return true;
    }

    private int cmdProcessor(byte[] buf, int dataSize, int bufPos) {
        byte[] cmdData = new byte[256];
        int cmdPos = 0;

        for(int i = bufPos; i < dataSize && cmdPos < 256; i++) {
            switch (buf[i]) {
                case PacketData.PACKET_HEAD_FLAG: {
                    logger.d( "cmdProcessor: PACKET_HEAD_FLAG");
                    curPacketData = new PacketData();
                }break;
                case PacketData.PACKET_TRAN_FLAG: {
                    logger.d( "cmdProcessor: PACKET_TRAN_FLAG");
                    cmdData[cmdPos++] = (byte) (buf[++i] - PacketData.PACKET_TRAN_FLAG);
                }break;
                case PacketData.PACKET_TAIL_FLAG: {
                    logger.d( "cmdProcessor: PACKET_TAIL_FLAG");
                    if (constructPacketData(cmdData, curPacketData, cmdPos)) {
                        if (curPacketData.isPacketValid) {
                            processPacketData(curPacketData);
                            curPacketData = null;
                        }
                    } else {
                        logger.d( "cmdProcessor: construct packet data not finish");
                    }

                    i++;

                    recvState = RECV_STATE_READ_DATA;
                    return i;
                }
                default:{
                    cmdData[cmdPos++] = buf[i];
                }break;
            }
        }

        logger.d( "cmdProcessor: bufPos:" + bufPos);
        return bufPos;
    }

    void processPacketData(PacketData data) {
        logger.d( "processPacketData: mainCmd: " + Integer.toHexString((int)data.mainCmd) +
                " subCmd:" + Integer.toHexString((int)data.subCmd));

        switch (data.mainCmd) {
            case SPP_MAIN_CMD_POC_TYPE: {
                int btKeyCode;
                byte keyCode = data.data[0];

                logger.d( "processPacketData: SPP_MAIN_CMD_POC_TYPE");
                if (data.subCmd == SPP_SUB_CMD_POC_KEY) {
                    BtDevCommonMsg btKeyEvent = BtDevCommonMsg.BT_DEV_COMMON_NONE;
                    btKeyCode = BtDevConstant.BT_KEY_CODE_PTT;
                    if (keyCode == KEYMSG_POC_PRESS) {
                        btKeyEvent = BtDevCommonMsg.BT_DEV_COMMON_KEY_PRESSED;
                    } else if (keyCode == KEYMSG_POC_RELEASE) {
                        btKeyEvent = BtDevCommonMsg.BT_DEV_COMMON_KEY_RELEASED;
                    }

                    if (getListener() != null) {
                        Message message = Message.obtain();
                        Bundle bundle = new Bundle();
                        message.what = btKeyEvent.getValue();
                        bundle.putInt(BtDevConstant.EXTRA_KEY_CODE, btKeyCode);
                        message.setData(bundle);
                        getListener().onMessage(this, message);
                    }
                } else if (data.subCmd == SPP_POC_POC_SUB_VOLUMN) {
                    byte volumn = data.data[0];
                    if (getListener() != null) {
                        Message message = Message.obtain();
                        Bundle bundle = new Bundle();
                        message.what = BtDevCommonMsg.BT_DEV_COMMON_VOLUMN_CHANGED.getValue();
                        bundle.putInt(BtDevConstant.EXTRA_VOLUMN_VALUE, volumn);
                        message.setData(bundle);
                        getListener().onMessage(this, message);
                    }
                }
            }
            break;

            case SPP_MAIN_CMD_KEY_TYPE: {
                int btKeyCode = BtDevConstant.BT_KEY_CODE_UNKNOWN;
                byte keyCode = data.data[0];
                logger.d( "processPacketData: SPP_MAIN_CMD_KEY_TYPE");
                logger.d( "processPacketData: keyCode:" + Integer.toHexString((int) keyCode));
                switch (keyCode) {
                    case KEYMSG_KEY_NEXT:
                        btKeyCode = BtDevConstant.BT_KEY_CODE_NEXT;
                        break;
                    case KEYMSG_KEY_PREV:
                        btKeyCode = BtDevConstant.BT_KEY_CODE_PREV;
                        break;
                    case KEYMSG_KEY_VOL_DOWN:
                        btKeyCode = BtDevConstant.BT_KEY_CODE_VOLUME_DOWN;
                        break;
                    case KEYMSG_KEY_VOL_UP:
                        btKeyCode = BtDevConstant.BT_KEY_CODE_VOLUME_UP;
                        break;
                    case KEYMSG_KEY_ACCEPT:
                        btKeyCode = BtDevConstant.BT_KEY_CODE_ACCEPT;
                        break;
                    case KEYMSG_KEY_REJECT:
                        btKeyCode = BtDevConstant.BT_KEY_CODE_REJECT;
                        break;
                    case KEYMSG_KEY_SOS:
                        btKeyCode = BtDevConstant.BT_KEY_CODE_SOS;
                        break;
                    case KEYMSG_KEY_ANCHOR:
                        btKeyCode = BtDevConstant.BT_KEY_CODE_ANCHOR;
                        break;
                    default:
                        break;
                }

                if (btKeyCode == BtDevConstant.BT_KEY_CODE_UNKNOWN) {
                    logger.d( "processPacketData: KEY_EVENT_UNKNOWN");
                }else {
                    if (getListener() != null) {
                        Message message = Message.obtain();
                        Bundle bundle = new Bundle();
                        bundle.putInt(BtDevConstant.EXTRA_KEY_CODE, btKeyCode);
                        message.setData(bundle);
                        message.what = BtDevCommonMsg.BT_DEV_COMMON_KEY_CLICKED.getValue();
                        getListener().onMessage(this, message);
                    }
                }
            }
            break;
        }
    }

    private int processRecvBuf(byte[] buf, int dataLen) {
        int curPos = 0;
        int processPos = 0;

        while(curPos < dataLen) {
            logger.d( "processRecvBuf: recvState:" + recvState);
            switch (recvState) {
                case RECV_STATE_READ_INIT: {
                    logger.d( "processRecvBuf: RECV_STATE_READ_INIT");
                    processPos = initProcessor(buf, dataLen, curPos);
                    if (processPos == curPos) {
                        return curPos;
                    }
                }
                break;

                case RECV_STATE_READ_DATA: {
                    logger.d( "processRecvBuf: RECV_STATE_READ_DATA");
                    processPos = dataProcessor(buf, dataLen, curPos);
                    if(recvState == RECV_STATE_READ_DATA) {
                        return processPos;
                    }
                }
                break;

                case RECV_STATE_READ_AUDIO: {
                    logger.d( "processRecvBuf: RECV_STATE_READ_AUDIO");
                    processPos = audioProcessor(buf, dataLen, curPos);
                    if(processPos == curPos) {
                        return curPos;
                    }
                }
                break;

                case RECV_STATE_READ_CMD: {
                    logger.d( "processRecvBuf: RECV_STATE_READ_CMD");
                    processPos = cmdProcessor(buf, dataLen, curPos);

                    if(processPos == curPos) {
                        return curPos;
                    }
                }
                break;
            }
            curPos = processPos;
        }

        return curPos;
    }

    @Override
    protected void onSppDataRecv ( byte[] buffer, int bufferSize){
        int curPos = 0;

        logger.d("curRecvOffset:" + curRecvSize + " bufferSize:" + bufferSize);
        if (recvBuf != null) {
            if (bufferSize + curRecvSize < MAX_RECVBUF_SIZE) {
                try {
                    System.arraycopy(buffer, 0, recvBuf, curRecvSize, bufferSize);
                    curRecvSize += bufferSize;
                    curPos = processRecvBuf(recvBuf, curRecvSize);
                    logger.d("curPos:" + curPos);

                    if (curPos < curRecvSize) {
                        for (int i = curPos, j = 0; i < curRecvSize; i++, j++) {
                            recvBuf[j] = recvBuf[i];
                        }
                    }

                    curRecvSize -= curPos;
                } catch (Exception e) {
                    logger.e("there is some exception happen in onSppDataRecv " + e.getMessage());
                    logger.e("curRecvSize=" + curRecvSize + " curPos=" + curPos);
                    e.printStackTrace();
                    disconnectSpp();
                    connectSpp();
                }
            }
        }
    }

    @Override
    protected int getMaxSppPacketDataSize () {
        return PacketData.MAX_SPP_PACKET_SIZE;
    }

    @Override
    public BtRecorderInterface getRecorder(int recorderType) {
        if (recorderType == SPP_RECORDER) {
            btSppRecorder = new BtSppRecorder();
            return btSppRecorder;
        } else if (recorderType == SCO_RECORDER) {
            btScoRecorder = new BtScoRecorder();
            return btScoRecorder;
        }

        return null;
    }

    @Override
    protected UUID getSppConnectUUID () {
        return UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
    }

    @Override
    protected void onBtConnectStateChanged ( int profile, int curState){
        super.onBtConnectStateChanged(profile, curState);
        logger.d( "onBtConnectStateChanged: " + profile + " " + curState);
        if (profile == BluetoothProfile.HEADSET) {
            if (curState == BluetoothProfile.STATE_CONNECTED) {
                connectSpp();
            }else {
                handMicConnected = false;
            }
        }
    }

    @Override
    public void openDevice() {
        super.openDevice();
        logger.d( "openDevice: ");
        recvBuf = new byte[MAX_RECVBUF_SIZE];
    }

    @Override
    public void closeDevice() {
        super.closeDevice();
        logger.d( "closeDevice: ");
        recvBuf = null;
        handMicConnected = false;
    }

    private int constructSendingData(PacketData sentData, byte[] sendingBuf, int sentSize) {
        int packetLen = 0, i, j = 0;
        short checkSum = (byte)0;
        byte[] temp = new byte[PacketData.MAX_SPP_PACKET_SIZE];

        temp[packetLen++] = (byte)((sentSize + 7) & 0xff);
        temp[packetLen++] = (byte)(((sentSize + 7) & 0xff00) >> 8);
        temp[packetLen++] = sentData.mainCmd;
        temp[packetLen++] = sentData.subCmd;

        if(sentData.preSendDataOffset > 0) {
            temp[packetLen++] = sentData.packetId;
        }
        else {
            temp[packetLen++] = (byte) (sentData.packetId | 0x80);
        }

        sentData.packetId++;
        if(sentData.preSendDataOffset > 0) {
            temp[packetLen++] = (byte)(sentData.preSendDataOffset & 0xff);
            temp[packetLen++] = (byte)((sentData.preSendDataOffset & 0xff00) >> 8);
        } else {
            temp[packetLen++] = (byte)(sentData.dataSize & 0xff);
            temp[packetLen++] = (byte)((sentData.dataSize & 0xff00) >> 8);
        }

        for(i = 0; i < packetLen; i++) {
            checkSum += ((short)temp[i] & 0xFF);
        }

        for(i = 0; i < sentSize; i++) {
            temp[packetLen++] = sentData.data[sentData.preSendDataOffset + i];
            checkSum += ((short)sentData.data[sentData.preSendDataOffset + i] & 0xFF);
        }

        logger.d( "constructSendingData: checkSum:" + checkSum);
        temp[packetLen++] = (byte)(checkSum & 0xff);
        temp[packetLen++] = (byte)((checkSum & 0xff00) >> 8);

        sendingBuf[j++] = PacketData.PACKET_HEAD_FLAG;

        for(i = 0; i < packetLen; i++) {
            switch (temp[i]) {
                case PacketData.PACKET_HEAD_FLAG:
                case PacketData.PACKET_TRAN_FLAG:
                case PacketData.PACKET_TAIL_FLAG: {
                    sendingBuf[j++] = PacketData.PACKET_TRAN_FLAG;
                    sendingBuf[j++] = (byte) (PacketData.PACKET_TRAN_FLAG + temp[i]);
                }
                break;
                default: {
                    sendingBuf[j++] = temp[i];
                }
                break;
            }
        }

        sendingBuf[j++] = PacketData.PACKET_TAIL_FLAG;

        return j;
    }

    private void sendPacketInternal(PacketData packetData) {
        byte[] buffer = new byte[MAX_PACKET_SIZE];
        if(packetData.dataSize == 0) {
            int sentSize = constructSendingData(packetData, buffer, 0);
            putSppSendData(buffer, sentSize);
        }else{
            int sentSize = 0;
            while(packetData.sendDataOffset < packetData.dataSize) {
                if(packetData.sendDataOffset + PacketData.MAX_SPP_SEND_ONESIZE > packetData.dataSize) {
                    sentSize = packetData.dataSize - packetData.sendDataOffset;
                }else{
                    sentSize = PacketData.MAX_SPP_SEND_ONESIZE;
                }

                packetData.preSendDataOffset = packetData.sendDataOffset;
                packetData.sendDataOffset += sentSize;

                sentSize = constructSendingData(packetData, buffer, sentSize);
                putSppSendData(buffer, sentSize);
            }
        }
    }

    private boolean sendData(byte mainCmd, byte subCmd, byte[] data, int dataSize) {
        PacketData packetData;
        packetData = new PacketData(mainCmd, subCmd, data, dataSize);
        sendPacketInternal(packetData);
        return true;
    }

    public boolean sendPocCmd(byte cmd, byte param) {
        byte[] data = new byte[2];
        data[0] = cmd;
        data[1] = param;
        return sendData(WLHandMicConstant.SPP_PHONE_STATE_MAIN_CMD, WLHandMicConstant.SPP_PHONE_STATE_SUB_POCCMD, data,2);
    }

    public boolean sendPocCurState(byte state) {
        byte[] data = new byte[1];
        data[0] = state;
        return sendData(WLHandMicConstant.SPP_PHONE_STATE_MAIN_CMD, WLHandMicConstant.SPP_PHONE_STATE_SUB_CURSTATE, data, 1);
    }

    public boolean sendName(String name, byte nameType) {
        byte[] localData = null;
        int localDataSize = 0;
        try {
            if (isV200) {
                localData = name.getBytes("UnicodeLittleUnmarked");
            } else {
                localData = name.getBytes("gb2312");
            }
            localDataSize = localData.length;
        }catch (UnsupportedEncodingException e){
            return false;
        }
        return sendData(WLHandMicConstant.SPP_PHONE_INFO_MAIN_CMD, nameType, localData, localDataSize);
    }

    public boolean sendSleepInterval(byte subCmd, short interval) {
        byte [] data = new byte[2];
        data[0] = (byte)(((interval & 0xff00) >> 8) & 0xff);
        data[1] = (byte)(interval & 0xff);
        return sendData(WLHandMicConstant.SPP_PHONE_CONFIGURATION_CMD, subCmd, data,2);
    }

    public boolean sendSystemTime() {
        byte[] cmd = new byte[4];
        Calendar cal = Calendar.getInstance();
        cmd[0] = (byte)(cal.get(Calendar.HOUR_OF_DAY) & 0xFF);
        cmd[1] = (byte)(cal.get(Calendar.MINUTE) & 0xFF);
        cmd[2] = (byte)(cal.get(Calendar.SECOND) & 0xFF);
        logger.d( "sendSystemTime: " + cmd[0] + " " + cmd[1] + " " + cmd[2]);
        return sendData(WLHandMicConstant.SPP_PHONE_INFO_MAIN_CMD, WLHandMicConstant.SPP_PHONE_INFO_SUB_TIME, cmd, 3);
    }

    /**
     * 0 简体 1 繁体 2 英文
     * @param langType
     * @return
     */
    public boolean sendLangType(byte langType) {
        byte [] data = new byte[1];
        if(langType > (byte)2) {
            data[0] = 1;
            return false;
        }
        data[0] = langType;
        return sendData(WLHandMicConstant.SPP_PHONE_CONFIGURATION_CMD, WLHandMicConstant.SPP_PHONE_CONFIG_SUB_LANGUAGE, data,1);
    }

    private void setToneVolume(int volume) {
        byte[] data = new byte[1];

        if(volume > (byte)8) {
            data[0] = 8;
        } else if (volume >= 0) {
            data[0] = (byte)volume;
        }

        sendData(WLHandMicConstant.SPP_PHONE_CONFIGURATION_CMD, WLHandMicConstant.SPP_PHONE_CONFIG_SUB_VOICE_GAIN, data, 1);
    }

    /*
     *   @author jack chen
     *   create at 19-5-8 下午2:46
     *   description:
     *      设置手咪提示音静音
     *    * @param isMute 提示音静音
     *   return void
     */
    public void setToneMute(boolean isMute) {
        if (handMicConnected) {
            isToneMute = isMute;
            if (isMute) {
                setToneVolume(0);
            } else {
                setToneVolume();
            }
        }
    }

    public void setToneVolume() {
        int maxVolume = BtHelper.getInstance().getMaxToneVolume();
        int curVolume = BtHelper.getInstance().getCurrentToneVolume();
        //提示音音量最大为四级
        if (0 == curVolume || isToneMute) {
            setToneVolume(0);
        } else if (curVolume <= maxVolume/3) {
            setToneVolume(1);
        } else if (curVolume <= (maxVolume/2)) {
            setToneVolume(2);
        } else if (curVolume <= maxVolume*3/5) {
            setToneVolume(3);
        } else if (curVolume <= maxVolume*3/4) {
            setToneVolume(4);
        } else if (curVolume <= maxVolume){
            setToneVolume(5);
        }
    }

    private void sppHeartbeat() {
        byte[] heartbeat = new byte[2];
        heartbeat[0] = 0x44;
        heartbeat[1] = 0x44;
        putSppSendData(heartbeat, 2);
    }

    @Override
    public String getDeviceType() {
        return "WL100 Device";
    }

    @Override
    public String getProtocolName() {
        return IBtConstants.PROTOCOL_VOIS;
    }

    /*
     *   @author jack chen
     *   create at 19-5-8 下午2:40
     *   description:
     *      本函数主要在对讲讲话时调用，用于开启手咪音频通路
     *    * @param talker 讲话人名称 本人讲话建议为"您正在讲话"
     *   return void
     */
    public void burstTalk(String talker) {
        if (handMicConnected) {
            sendPocCurState(WLHandMicConstant.POC_STATE_OUT_CONNECTED);
            sendName(talker, WLHandMicConstant.SPP_PHONE_INFO_SUB_OWNER_NAME);
        }else {
            logger.e("handMicConnected == false!!!");
        }
    }

    /*
     *   @author jack chen
     *   create at 19-5-8 下午2:41
     *   description:
     *      本函数主要在对讲接听时调用，用于开启手咪音频通路
     *    * @param talker 讲话人名称
     *   return void
     */
    public void burstListen(String talker) {
        if (handMicConnected) {
            sendPocCurState(WLHandMicConstant.POC_STATE_IN_CONNECTED);
            sendName(talker, WLHandMicConstant.SPP_PHONE_INFO_SUB_PEER_NAME);
        }
    }

    /*
     *   @author jack chen
     *   create at 19-5-8 下午2:41
     *   description:
     *      本函数主要在对讲释放或接听结束时调用，用于关闭手咪音频通路
     *    * @param
     *   return void
     */
    public void burstIdle() {
        if (handMicConnected) {
            sendPocCurState(WLHandMicConstant.POC_STATE_DISCONNECTED);
        }
    }

    /*
     *   @author jack chen
     *   create at 19-5-8 下午2:42
     *   description:
     *      本函数在收到对讲来电调用，手咪将显示对讲来电名称
     *      会激活摘机、挂机按键，用户可通话手咪摘机、挂机控制来电操作
     *    * @param name 来电名称
     *   return void
     */
    public void incomingCall(String name) {
        if (handMicConnected) {
            sendName(name, WLHandMicConstant.SPP_PHONE_INFO_SUB_INCOMMING_NAME);
            sendPocCmd(WLHandMicConstant.POC_CMD_INCOMING, (byte) 0x0);
        }
    }

    /*
     *   @author jack chen
     *   create at 19-5-8 下午2:43
     *   description:
     *      本函数在来电处理完成时调用，比如接听来电、拒接来电、来电中断等事件均需调用同时超过60s未处理会自行断开来电处理
     *    * @param
     *   return void
     */
    public void finishIncomingCall() {
        if (handMicConnected) {
            sendPocCmd(WLHandMicConstant.POC_CMD_INCOMING, (byte) 0x1);
        }
    }

    /*
     *   @author jack chen
     *   create at 19-5-8 下午2:43
     *   description:
     *      本函数用于设置当前活动会话名称，应与PTT按键响应会话保持一致
     *      如用户未连接活动会话时，建议设置为"会话未连接"等
     *    * @param chatName 当前会话名称
     *   return void
     */
    public void chatAttach(String chatName) {
        if (handMicConnected) {
            sendName(chatName, WLHandMicConstant.SPP_PHONE_INFO_SUB_GROUP_NAME);
        }
    }

    /*
     *   @author jack chen
     *   create at 19-5-8 下午2:44
     *   description:
     *      屏幕灭屏等待时间 30~1800s
     *    * @param interval
     *   return void
     */
    public void setScreenSleepInterval(int interval) {
        if (handMicConnected) {
            if (interval > 1800) {
                interval = 1800;
            } else if (interval < 10) {
                interval = 10;
            }
            sendSleepInterval(WLHandMicConstant.SPP_PHONE_CONFIG_SUB_SCREEN_SLEEP, (short) interval);
        }
    }

    /*
     *   @author jack chen
     *   create at 19-5-8 下午2:45
     *   description:
     *      手咪休眠间隔时间 60~3600
     *    * @param interval
     *   return void
     */
    public void setNormalSleepTime(int interval) {
        if (handMicConnected) {
            sendSleepInterval(WLHandMicConstant.SPP_PHONE_CONFIG_SUB_NORMAL_SLEEP, (short) interval);
        }
    }

    /*
     *   @author jack chen
     *   create at 19-5-8 下午2:45
     *   description:
     *      手咪休眠间隔时间 600~36000
     *    * @param interval
     *   return void
     */
    public void setDepthSleepTime(int interval) {
        if (handMicConnected) {
            sendSleepInterval(WLHandMicConstant.SPP_PHONE_CONFIG_SUB_DEEP_SLEEP, (short) interval);
        }
    }

    public boolean isV200() {
        return isV200;
    }

    public String getHandMicVersion() {
        return handMicVersion;
    }

    @Override
    public int getDefaultRecorderType() {
        return SPP_RECORDER;
    }

    @Override
    public boolean isNeedHeartbeat() {
        return false;
    }

    @Override
    public void setSeqID(String seqID) {

    }

    @Override
    public void getVendor() {

    }

    @Override
    public void getVersion() {

    }

    @Override
    public boolean startRecorder(ResultCallback callback) {
        if (callback != null) {
            callback.onResult(true);
        }

        return true;
    }

    @Override
    public void stopRecorder(ResultCallback callback) {
        if (callback != null) {
            callback.onResult(true);
        }
    }
}
